﻿// Helper class that detects dice combinations based on the passed in dice
// 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace GeneralTheGame
{
    public static class CombinationDetection
    {
        // A combination list that holds the pairs, three of a kind and four of a kind combinations
        // Lone Wolves is deprecated and not used anymore
        private static List<List<int>> combinations = new List<List<int>>()
    {
        new List<int>(), // lone wolves
        new List<int>(), // first pair
        new List<int>(), // second pair
        new List<int>(), // three of a kind
        new List<int>(), // four of a kind
    };

        // Bool values that indicate if theres a Generale (five of a kind)
        // Small straight, large straight or full house found
        // Full house detection is based on finding 2 pairs and three of a kind
        private static bool generale = false;
        private static bool smallStraight = false;
        private static bool largeStraight = false;
        private static bool fullHouse = false;

        // Holds whether there is already a pair found
        // If there is, switches the pair filling to the second pair collection
        private static bool firstPairAdded = false;

        // Detects combinations and returns a collection holding scores for each combination
        // The List<Die> collection is intented to be the player dice collection
        public static List<int> DetectCombinations(List<Die> dies)
        {
            // A loop iterating over the passed in dice
            // Assumes that there are 5 dice
            for (int i = 0; i < 4; i++)
            {
                int currentThrow = dies[i].GetLastThrow();

                // Holds the number of equal dice found
                int equalityCount = 1;

                // A collection of the equal dice indexes
                var diceIndex = new List<int>();

                // Starts by adding the current die
                diceIndex.Add(i);

                // Loops over the rest of the dice and checks whether they mach the current die
                for (int j = i + 1; j < 5; j++)
                {
                    // If they are matches found, increment the equality count
                    // and add the die index to the index list
                    if (dies[j].GetLastThrow() == currentThrow)
                    {
                        equalityCount++;
                        diceIndex.Add(j);
                    }
                }

                // Switches over the equality count
                switch (equalityCount)
                {
                        // if there are two found matches,
                        // add them to the first or the second pair collection respectively
                    case 2:
                        if (!firstPairAdded)
                        {
                            combinations[1].AddRange(diceIndex);
                            firstPairAdded = true;
                        }
                        else
                        {
                            combinations[2].AddRange(diceIndex);
                        }
                        break;
                        // if there are three found matches,
                        // add them to the three of a kind collection
                    case 3:
                        combinations[3].AddRange(diceIndex);
                        break;
                        // if there are four found matches,
                        // add them to the three of a kind collection
                    case 4:
                        combinations[4].AddRange(diceIndex);
                        break;
                        // if there are five matches
                        // set generale to true
                    case 5:
                        generale = true;
                        break;
                    default:
                        break;
                }
            }

            // Checks for straights and full houses
            CheckForStraight(dies);
            CheckForFullHouse();

            // Calculates the score and saves it in a list of ints
            var result = CalculateTableScore(dies);

            // returns the resulting list
            return result;
        }

        // Calculates the score for each combination depending on the combination collections filled
        private static List<int> CalculateTableScore(List<Die> dies)
        {
            var scoreList = new List<int>();

            // Score for ones to sixes
            // Loops from 1 to 6 to allow easy dice value check
            for (int i = 1; i < 7; i++)
            {

                // Start with the minimum achievable score
                // For ones it's -2
                // For twos -4 and so forth
                // Increment it by the current dice score each time it's matched
                int scoreHolder = (i * 3) * -1;
                for (int j = 0; j < dies.Count; j++)
                {
                    if (dies[j].GetLastThrow() == i)
                    {
                        scoreHolder += i;
                    }
                }
                scoreList.Add(scoreHolder);
            }


            // Score for pairs, three of a kind and four of a kind
            for (int i = 1; i < 5; i++)
            {

                // holds the score for the current combination
                // for the non-mandatory combinations the score cannot be negative
                int scoreHolder = 0;

                if (combinations[i].Count > 0)
                {
                    // Case for one pair
                    if (i == 1)
                    {
                        // calculates the score for a single pair
                        // first calculates the score for the first pair
                        // if there is a second pair available, checks if it's score is not higher than the one of the first pair
                        // if it is, sets the score holder to the second pair score
                        scoreHolder = dies[combinations[i][0]].GetLastThrow() * 2;
                        if (combinations[2].Count > 0 && (dies[combinations[2][0]].GetLastThrow() * 2) > scoreHolder)
                        {
                            scoreHolder = dies[combinations[2][0]].GetLastThrow() * 2;
                        }
                    }
                    // Case for two pairs
                    else if (i == 2)
                    {
                        // Calculates the score for two pairs by adding the first and the second pair score
                        scoreHolder = (dies[combinations[1][0]].GetLastThrow() * i) + (dies[combinations[i][0]].GetLastThrow() * i);
                    }
                    // Case for three and four of a kind
                    else
                    {
                        // Calculates the score by multiplying the die value by the current loop iteration
                        scoreHolder = dies[combinations[i][0]].GetLastThrow() * i;
                    }
                }

                scoreList.Add(scoreHolder);
            }

            int currentScore = 0;

            // Score for full house
            // Full house calculation occurs when calculating Chance combination, since the score is essentially the same
            scoreList.Add(currentScore);

            // Small Straight score
            if (smallStraight == true)
            {
                currentScore = 15;
            }

            scoreList.Add(currentScore);
            currentScore = 0;

            // Large straight score
            if (largeStraight == true)
            {
                currentScore = 20;
            }

            scoreList.Add(currentScore);
            currentScore = 0;

            // Chance combination score
            for (int i = 0; i < 5; i++)
            {
                currentScore += dies[i].GetLastThrow();
            }

            scoreList.Add(currentScore);

            // Check for full house
            if (fullHouse == true)
            {
                scoreList[10] = currentScore;
            }

            currentScore = 0;

            if (generale == true)
            {
                currentScore = (dies[0].GetLastThrow() * 5) + 50;
            }

            scoreList.Add(currentScore);

            // Resets the combinations
            ResetCombinations();

            // Returns the score list
            return scoreList;
        }

        // Resets all collections in preperation for the next combination detection
        // Since this is a static class, if the collections are not reset 
        // there will be collision of data on the next combination check
        private static void ResetCombinations()
        {
            foreach (var list in combinations)
            {
                list.Clear();
            }

            smallStraight = false;
            largeStraight = false;
            fullHouse = false;
            generale = false;

            firstPairAdded = false;
        }

        // Checks if there is a straight combination available
        private static void CheckForStraight(List<Die> dies)
        {

            // First get all dice throws and fill them in an array
            int[] dieRolls = new int[5];
            for (int i = 0; i < 5; i++)
            {
                dieRolls[i] = dies[i].GetLastThrow();
            }

            // Sort the array for easier progression check
            Array.Sort(dieRolls);

            // Initialize sum equal to the first element in the sorted array
            int sum = dieRolls[0];

            // Check if the dice array is a progressive sequence
            // and calculate it's sum
            bool isProgressiveSequence = true;
            for (int i = 0; i < dieRolls.Length - 1; i++)
            {
                if (dieRolls[i] + 1 != dieRolls[i + 1])
                {
                    isProgressiveSequence = false;
                    break;
                }
                sum += dieRolls[i + 1];
            }

            // If the sum is 15 and the sequence is progressive, set small straight to true
            // Total small straight sum is always 15
            if (isProgressiveSequence == true && sum == 15)
            {
                smallStraight = true;
            }
                // otherwise if the sum is 20 it's a large straight
                // Total large straight sum is always 20
            else if (isProgressiveSequence == true && sum == 20)
            {
                largeStraight = true;
            }
        }

        // Checks if there is a full house available
        private static void CheckForFullHouse()
        {
            // If there are two available pairs and a three of a kind, there is a full house availble
            // Since if there are two available pairs, that means that there are at least two sets with different values
            // And if there is a three of a kind available, that ensures that there is at least one pair that has
            // different members than the other pair and the three of a kind
            if (combinations[1].Count > 0 && combinations[2].Count > 0 && combinations[3].Count > 0)
            {
                fullHouse = true;
            }
        }

        // Checks if there are values unused in any combination
        // Not used and deprecated
        //private static void CheckLoneWolves(List<Die> dies)
        //{
        //    if (smallStraight == true || largeStraight == true)
        //    {
        //        return;
        //    }
        //    for (int i = 0; i < dies.Count; i++)
        //    {
        //        bool flag = false;
        //        foreach (var list in combinations)
        //        {
        //            if (list.Contains(i))
        //            {
        //                flag = true;
        //            }
        //        }

        //        if (!flag)
        //        {
        //            combinations[0].Add(i);
        //        }
        //    }
        //}
    }
}
